﻿using FluentFTP;
using FluentFTP.Exceptions;

namespace Digitalmes.Infrastructure.Ftp;

/// <summary>
/// Fluent FTP 客户端。
/// </summary>
/// <param name="options"></param>
public sealed class FluentFtpClient(IOptions<FtpOptions> options) : IFluentFtpClient
{
    public IAsyncFtpClient Client { get; }
        = new AsyncFtpClient(options.Value.Host, options.Value.Username, options.Value.Password, options.Value.Port);

    public async Task<bool> UploadFileAsync(
        string localPath,
        string remotePath, 
        bool isOverwrite = true, 
        bool createRemoteDir = false, 
        CancellationToken cancellationToken = default)
    {
        if (!Client.IsConnected)
        {
            await Client.AutoConnect(cancellationToken);
        }

        var status = await Client.UploadFile(
            localPath, 
            remotePath, 
            existsMode: isOverwrite ? FtpRemoteExists.Overwrite : FtpRemoteExists.Skip, 
            createRemoteDir: createRemoteDir, 
            token: cancellationToken);
        return status is FtpStatus.Success || (!isOverwrite && status is FtpStatus.Skipped);
    }

    public async Task<bool> DownloadFileAsync(
        string localPath, 
        string remotePath,
        bool isOverwrite = true, 
        CancellationToken cancellationToken = default)
    {
        if (!Client.IsConnected)
        {
            await Client.AutoConnect(cancellationToken);
        }

        var status = await Client.DownloadFile(
            localPath, 
            remotePath, 
            existsMode: isOverwrite ? FtpLocalExists.Overwrite : FtpLocalExists.Skip, 
            token: cancellationToken);
        return status is FtpStatus.Success || (!isOverwrite && status is FtpStatus.Skipped);
    }

    public async Task<bool> DeleteFileAsync(string remotePath, CancellationToken cancellationToken = default)
    {
        if (!Client.IsConnected)
        {
            await Client.AutoConnect(cancellationToken);
        }

        try
        {
            await Client.DeleteFile(remotePath, cancellationToken);
            return true;
        }
        catch (Exception ex) when (ex is FtpCommandException)
        {
            return false;
        }
    }

    public async ValueTask DisposeAsync()
    {
        await Client.DisposeAsync();
    }
}
